# -*- coding: utf-8 -*-
# @Time : 2024/4/7 18:55
# @Author : wangya
# @Email : wangya1907@163.com
# @File : yt_crawl.py
# @Project : YouTubeDownload-master
import random
import csv
import subprocess
import re
import concurrent.futures
import logging
import platform
import requests
import os

logging.basicConfig(filename='error.log', level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')
save_path = r'video'

def write_csv(csv_file_path, info):
    # 将提取的视频 ID 写入 CSV 文件
    with open(csv_file_path, 'a', newline='', encoding='utf-8') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow([info])


def retry_request(url, headers=None, max_retries=3):
    """重试请求函数"""
    retries = 0
    while retries < max_retries:
        try:
            if headers:
                return requests.get(url, headers=headers)
            else:
                return requests.get(url)
        except (requests.exceptions.ConnectTimeout, requests.exceptions.ConnectionError,
                requests.exceptions.ReadTimeout, requests.exceptions.SSLError,
                requests.exceptions.MissingSchema, requests.exceptions.ChunkedEncodingError):
            logging.info(u"网络不稳定 正在重试")
            retries += 1
    return None


def get_video_info(url):
    """从网页中获取视频 ID"""
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0'
    }
    res = retry_request(url, headers=headers)
    if not res:
        return []
    res_text = res.text
    reg = re.compile(r'"url":"/watch\?v=(.*?)"', re.S)
    video_ids = reg.findall(res_text)
    return video_ids


def get_error_id(file_path="error.log"):
    """从错误日志文件中获取错误的视频 ID"""
    try:
        with open(file_path, mode='r', encoding='utf-8') as file:
            read_lines = file.readlines()
            error_id = []
            pattern2 = r'视频id:(.*?), 错误信息'
            for line in read_lines:
                match =re.search(pattern2, line)
                if match:
                    error_id.append(match.group(1))
                else:
                    print('%s 无法识别' % line)
            return list(set(error_id))
    except FileNotFoundError:
        return []


def read_csv_ids(csv_file):
    """从 CSV 文件中读取视频 ID"""
    ids = set()
    with open(csv_file, newline='', encoding='utf-8') as csvfile:
        reader = csv.reader(csvfile)
        for row in reader:
            # 假设视频 ID 在 CSV 文件的第一列
            video_id = row[0].strip()
            if video_id:
                ids.add(video_id)
    return ids


def find_missing_ids(csv_ids, directory):
    """找出在 CSV 中但不在目录中的 ID"""
    missing_ids = set(csv_ids)  # 初始化为所有 CSV 中的 ID
    for root, dirs, files in os.walk(directory):
        for filename in files:
            for video_id in csv_ids:
                if video_id in filename:
                    write_csv("downloaded.csv", video_id)                                                       
                    missing_ids.discard(video_id)  # 如果找到 ID，从 missing_ids 中移除
    return missing_ids


def video_download(item):
    """下载视频的函数"""
    try:
        if item in read_csv_ids("downloaded.csv"):
            return f'{item} 已下载，跳过'
        url = f"https://www.youtube.com/watch?v={item}"
        command = f"yt-dlp {url} --cookies-from-browser chrome:'C:/Users/wangy/AppData/Local/Google/Chrome/User Data/Default' -o '{save_path}/%(uploader)s/%(title)s-%(id)s.%(ext)s'"
        # command = f"python script.py -u {item} -o {save_path}/ -f {item}"
        result = subprocess.run(command, shell=True, capture_output=True, text=True)
        if result.returncode != 0:
            # error_info = re.findall(r'pytube\.exceptions.*:(.*)', result.stderr)
            # if error_info:
            #     logging.error(f'{item}, 错误：{error_info[0]}')
            logging.error(f"命令执行失败，返回码：{result.returncode}，视频id:{item}, 错误信息{result}")
            return f"命令执行失败，返回码：{result.returncode}，视频id:{item}, 错误信息{result}"
        else:
            write_csv("downloaded.csv", item)
            return f'{item} 下载成功'
    except Exception as e:
        logging.error(f'{item}, 错误：{e}')
        return f'捕获到异常: {e}'


def id_generator(error_id, downloaded_id, all_ids):
    """生成未下载且未出错的视频 ID"""
    for item in all_ids:
        if item not in error_id and item not in downloaded_id:
            yield item


if __name__ == '__main__':
    # 选择从 CSV 文件还是网页获取视频 ID
    id_gen = find_missing_ids(read_csv_ids("video_ids.csv"), save_path)
    # csv_ids = get_video_info("https://www.youtube.com/@jaybyrdfilms/videos")
    error_ids = get_error_id("error.log")
    error_id_set = set(error_ids)
    print(id_gen)
    with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
        futures = [executor.submit(video_download, item) for item in id_gen]
        for future in concurrent.futures.as_completed(futures):
            try:
                content = future.result()
                print(content)
            except Exception as e:
                print("An error occurred:", e)